package com.xquant.pricing.systerm.service;

import com.github.pagehelper.PageInfo;
import com.xquant.pricing.calc.entity.Task;
import com.xquant.pricing.calc.entity.TaskLog;
import com.xquant.pricing.calc.mapper.TaskMapper;
import com.xquant.pricing.utils.SpringJobFactory;
import com.xquant.common.engine.xPP.cxf.XQuantPPService;
import com.xquant.common.engine.xPP.cxf.XQuantPPStub;
import com.xquant.common.engine.xPP.cxf.webservice.RunTask;
import com.xquant.common.engine.xPP.cxf.webservice.RunTaskResponse;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class TaskService implements InitializingBean {
    private Scheduler scheduler;

    @Autowired
    private XQuantPPService ppService;

    @Autowired
    private SpringJobFactory springJobFactory;
    @Autowired
    private List<JobService> jobServiceList;
    @Autowired
    private TaskMapper taskMapper;

    private Map<String, JobService> jobServiceMap;

    private static final String JOB_GROUP_NAME = "Auto";
    private static final String TRIGGER_GROUP_NAME = "MY_TRIGGERGROUP_NAME";

    @Override
    public void afterPropertiesSet() throws Exception {
        jobServiceMap = new HashMap<>();
        jobServiceList.forEach(item -> {
            jobServiceMap.put(item.getJobType(), item);
        });
        SchedulerFactory schedulerfactory = new StdSchedulerFactory();
        try {
            scheduler = schedulerfactory.getScheduler();
            scheduler.setJobFactory(springJobFactory);
            //startAllTask();
        } catch (SchedulerException ex) {
        }
    }

    public PageInfo<Task> queryTaskListByPage(Map param) {
        String type = (String) param.get("type");
        String[] split = type.split(",");
        param.put("typeList",split);
        List<Task> lst = taskMapper.queryTaskList(param);
        return new PageInfo<>(lst);
    }

    public PageInfo<TaskLog> queryTaskLogListByPage(Map param) {
        List<TaskLog> lst = taskMapper.queryTaskLogList(param);
        return new PageInfo<>(lst);
    }

    public void addTask(Task task) {
        taskMapper.addTask(task);
    }

    public void updateTask(Task task) {
        taskMapper.updateTask(task);
        try {
            removeJob(task);
            if (task.getStatus() == 1) {
                scheduleTask(task);
            }
        } catch (Exception ex) {

        }
    }

    public void deleteTask(Task task) {
        taskMapper.deleteTask(task);
        try {
            removeJob(task);
        } catch (Exception ex) {

        }
    }

    public boolean executeTask(Task task) {
        JobDetail jobDetail = buildJobDetail(task, "Manual");
        Trigger trigger = TriggerBuilder.newTrigger()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0))
                .startNow()
                .build();
        try {
            scheduler.scheduleJob(jobDetail, trigger);
            return true;
        } catch (SchedulerException ex) {
            return false;
        }
    }

    public RunTaskResponse executeSyncTask(Task task) {

        XQuantPPStub stub = null;
        RunTaskResponse ret = null;
        try {
            RunTask runTask = new RunTask();
            runTask.setParam(new String(task.getContext().replace("{baseDate}", task.getBegDate()).getBytes("ISO-8859-1"), "ASCII"));

            stub = ppService.borrowStub();
            ret = stub.runTask(runTask);
        } catch (RemoteException ex) {
            if (stub != null) {
                ppService.setTimeOut(stub);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (stub != null) {
                ppService.returnStub(stub);
            }
        }
        return ret;
    }

    public void startAllTask() {
        try {
            Map param = new HashMap<>();
            param.put("status", 1);
            List<Task> lst = taskMapper.queryTaskList(param);
            for (int i = 0; i < lst.size(); i++) {
                Task task = lst.get(i);
                scheduleTask(task);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void scheduleTask(Task task) throws Exception {
        JobDetail jobDetail = buildJobDetail(task, JOB_GROUP_NAME);
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(task.getId().toString(), TRIGGER_GROUP_NAME)
                .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression()))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        // 启动
        if (!scheduler.isShutdown()) {
            scheduler.start();
        }
    }

    private JobDetail buildJobDetail(Task task, String jobGroup) {
        JobService service = jobServiceMap.get(task.getType());
        JobDetail jobDetail = JobBuilder.newJob(service.getClass())
//                .withIdentity(task.getId().toString(), jobGroup)
                .usingJobData("context", task.getContext())
                .usingJobData("begDate", task.getBegDate())
                .usingJobData("endDate", task.getEndDate())
                .usingJobData("offsetDays", task.getOffsetDays())
                .usingJobData("jobName", task.getName())
                .build();
        return jobDetail;
    }

    public void removeJob(Task task) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(task.getId().toString(), TRIGGER_GROUP_NAME);
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(task.getId().toString(), JOB_GROUP_NAME));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void addTaskLog(TaskLog taskLog) {
        taskMapper.addTaskLog(taskLog);
    }

    public void updateTaskLog(TaskLog taskLog) {
        taskMapper.updateTaskLog(taskLog);
    }

    public int insertTaskLog(TaskLog taskLog) {
        return taskMapper.insertTaskLog(taskLog);
    }
}
